grammar SysY;

/*===-------------------------------------------===*/
/* Lexer rules                                     */
/*===-------------------------------------------===*/

Comma: ',';

Const: 'const';
EmptyArray: '[' WS* ']';

fragment Decimal: [0-9];
fragment Octal: [0-7];
fragment Heximal: [0-9a-fA-F];
fragment NonZeroDecimal: [1-9];
fragment NonZeroHeximal: [1-9a-fA-F];

fragment DigitSequenceDecimal: Decimal+;
fragment FractionalConstantDecimal:
	DigitSequenceDecimal? '.' DigitSequenceDecimal
	| '.' DigitSequenceDecimal
	| DigitSequenceDecimal '.';
fragment ExponentPartDecimal: ('e' | 'E') ('+' | '-')? DigitSequenceDecimal;
fragment DecimalFloatConstant:
	FractionalConstantDecimal ExponentPartDecimal?
	| DigitSequenceDecimal ExponentPartDecimal;

fragment DigitSequenceHeximal: Heximal+;
fragment FractionalConstantHeximal:
	DigitSequenceHeximal? '.' DigitSequenceHeximal
	| '.' DigitSequenceHeximal;
fragment BinaryExponent: ('p' | 'P') ('+' | '-')? DigitSequenceDecimal;

fragment HeximalFloatConstant: ('0x' | '0X') FractionalConstantHeximal BinaryExponent
	| ('0x' | '0X') DigitSequenceHeximal BinaryExponent;

FloatConst: DecimalFloatConstant | HeximalFloatConstant;

IntConst:
	'0'
	| NonZeroDecimal Decimal*
	| '0' Octal+
	| ('0x' | '0X') Heximal+;

String: '"' (ESC | .)*? '"';

Ident: [a-zA-Z_] [a-zA-Z0-9_]*;

//EmptyArray: '[' ']';

fragment ESC: '\\"' | '\\\\';

WS: [ \t\r\n] -> skip;

LINE_COMMENT: '//' .*? '\r'? '\n' -> skip;
LINE_COMMENT_NONEWLINE: '//' .*? -> skip;
COMMENT: '/*' .*? '*/' -> skip;

/*===-------------------------------------------===*/
/* Syntax rules                                    */
/*===-------------------------------------------===*/

compUnit: compUnitItem* EOF;
compUnitItem: decl | funcDef;
decl: Const? bType varDef (Comma varDef)* ';';

bType: 'int' | 'float';
varDef: Ident ('[' constExp ']')* ('=' initVal)?;
initVal: exp | '{' (initVal ( Comma initVal)*)? '}';
funcDef: funcType Ident '(' funcFParams? ')' block;
funcType: 'void' | 'int' | 'float';
funcFParams: funcFParam (Comma funcFParam)*;
funcFParam: bType Ident (EmptyArray ('[' exp ']')*)?;
block: '{' blockItem* '}';
blockItem: decl | stmt;
stmt:
	lVal '=' exp ';'						# StmtAssign
	| exp? ';'								# StmtExp
	| block									# StmtBlock
	| 'if' '(' cond ')' stmt ('else' stmt)?	# StmtIfElse
	| 'while' '(' cond ')' stmt				# StmtWhile
	| 'break' ';'							# StmtBreak
	| 'continue' ';'						# StmtContinue
	| 'return' exp? ';'						# StmtReturn;
exp: addExp | String;
cond: lOrExp # LOrAsCond;
lVal: Ident ('[' exp ']')*;
primaryExp:
	'(' exp ')'	# ExpAsPri
	| number	# NumAsPri
	| lVal		# LValAsPri;
number: IntConst | FloatConst;
unaryExp:
	primaryExp								# PriAsUna
	| unaop = ('+' | '-' | '!') unaryExp	# OpUnaAsUna
	| Ident '(' funcRParams? ')'			# FuncCallAsUna;
funcRParams: exp (Comma exp)*;
mulExp:
	unaryExp									# UnaAsMul
	| mulExp mulop = ('*' | '/' | '%') unaryExp	# MulUnaAsMul;
addExp:
	mulExp								# MulAsAdd
	| addExp addop = ('+' | '-') mulExp	# AddMulAsAdd;
relExp:
	addExp												# AddAsRel
	| relExp relop = ('<' | '>' | '<=' | '>=') addExp	# RelAddAsRel;
eqExp:
	relExp								# RelAsEq
	| eqExp eqop = ('==' | '!=') relExp	# EqRelAsEq;
lAndExp: eqExp # EqAsLAnd | lAndExp '&&' eqExp # LAndEqAsLAnd;
lOrExp:
	lAndExp					# LAndAsLOr
	| lOrExp '||' lAndExp	# LOrLAndAsLOr;
// 和exp类似, 不过按照语言规范里说的不会定义类似const char* p = "114514"的常量 而仅仅是将字符串用作参数传递 因此没有推出String的分支
constExp: addExp # AddAsConst;